﻿using System;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using DevExpress.Xpf.Core;
using Loki.Commands;
using Loki.Engine;
using Loki.UI.Wpf.Resources;
using Loki.Utils;

namespace Loki.UI.Wpf
{
    public abstract class BootStrapper : Application
    {
        #region Log
        private ILog _Log = null;

        /// <summary>
        /// Gets the logger.
        /// </summary>
        /// <value>The logger.</value>
        protected ILog Log
        {
            get
            {
                if (_Log == null)
                {
                    Interlocked.CompareExchange(ref _Log, LokiServices.Logger.GetLogger(this.GetType().Name), null);
                }

                return _Log;
            }
        }
        #endregion

        #region Initializing
        public event EventHandler Initializing;

        protected virtual void OnInitializing(EventArgs e)
        {
            EventHandler L_Handler = Initializing;

            if (L_Handler != null)
            {
                L_Handler(this, e);
            }
        }

        #endregion

        #region Initialized
        public event EventHandler Initialized;

        protected virtual void OnInitialized(EventArgs e)
        {
            EventHandler L_Handler = Initialized;

            if (L_Handler != null)
            {
                L_Handler(this, e);
            }
        }

        #endregion

        public BootStrapper()
        {
            Startup += new StartupEventHandler(BootStrapperWPF_Startup);

            try
            {
                Commands = new CommandManager();

                Commands.Handle(ApplicationCommands.START, ApplicationStart_Execute);
                Commands.Handle(ApplicationCommands.EXIT, ApplicationExit_Execute);
                Commands.Handle(ApplicationCommands.MESSAGE, ApplicationMessage_Execute);
                Commands.Handle(ApplicationCommands.WARNING, ApplicationWarning_Execute);
                Commands.Handle(ApplicationCommands.ERROR, ApplicationError_Execute);

                DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(BootStrapper_DispatcherUnhandledException);
            }
            catch (Exception Ex)
            {
                LokiServices.Errors.LogError(Ex.Message, Log, Ex);
                Commands.Dispose();
                Application.Current.Shutdown(-1);
            }
        }

        private void BootStrapper_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            ApplicationCommands.ERROR.Execute(e.Exception);
            ExitApplication();
        }

        void BootStrapperWPF_Startup(object sender, StartupEventArgs e)
        {
            Initialize();
        }

        public virtual void Initialize()
        {
            OnInitializing(EventArgs.Empty);

            Log.Info("Initializing application");
            SpringWPFEngine L_Engine = new SpringWPFEngine();
            ContextHelper.DefineApplicationEngine(L_Engine, L_Engine);

            Log.DebugFormat("Loading data definitions from [{0}]", string.Join(", ", DataDefinitions));
            ContextHelper.LoadData(DataDefinitions);
            Log.DebugFormat("Loading model definitions from [{0}]", string.Join(", ", ModelDefinitions));
            ContextHelper.LoadModel(ModelDefinitions);
            Log.DebugFormat("Loading UI definitions from [{0}]", string.Join(", ", VMDefinitions));
            ContextHelper.LoadUI(VMDefinitions);
            Log.DebugFormat("Loading Templates definitions from [{0}]", string.Join(", ", TemplatesDefinitions));
            ContextHelper.LoadTemplates(TemplatesDefinitions);

            if (!string.IsNullOrEmpty(ThemeName))
            {
                ThemeManager.ApplicationThemeName = ThemeName;
            }

            var L_SkinURI = new Uri(" pack://application:,,,/Loki.UI.Wpf;component/Resources/LokiSkin.xaml");
            var L_ResourcesURI = new Uri(" pack://application:,,,/Loki.UI.Wpf;component/Resources/LokiResources.xaml");
            Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = L_SkinURI });
            Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = L_ResourcesURI });

            PreStart();
        }

        public virtual void PreStart()
        {
            OnInitialized(EventArgs.Empty);

            ApplicationCommands.START.Execute(null);
        }

        public abstract void Start();

        public virtual void ExitApplication()
        {
            Log.Info(LogStrings.BootStrapper_ApplicationExit);

            Application.Current.Shutdown();
        }

        #region Disposable
        /// <summary>
        /// Releases all resources used by an instance of the <see cref="BootStrapperWPF" /> class.
        /// </summary>
        /// <remarks>
        /// This method calls the virtual <see cref="Dispose(bool)" /> method, passing in <strong>true</strong>, and then suppresses 
        /// finalization of the instance.
        /// </remarks>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~BootStrapper()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases the unmanaged resources used by an instance of the <see cref="BootStrapperWPF" /> class and optionally releases the managed resources.
        /// </summary>
        /// <param name="P_Disposing">Sets <strong>true</strong> to release both managed and unmanaged resources; <strong>false</strong> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool P_Disposing)
        {

        }
        #endregion

        #region Commands
        private void ApplicationStart_Execute(object sender, CommandEventArgs e)
        {
            Start();
        }

        private void ApplicationExit_Execute(object sender, CommandEventArgs e)
        {
            ExitApplication();
        }

        private void ApplicationMessage_Execute(object sender, CommandEventArgs e)
        {
            MessageBoxes.Message(e.Parameter.ToString());
        }

        private void ApplicationWarning_Execute(object sender, CommandEventArgs e)
        {
            MessageBoxes.Warning(e.Parameter.ToString());
        }

        private void ApplicationError_Execute(object sender, CommandEventArgs e)
        {
            Exception L_Ex = e.Parameter as Exception;
            if (L_Ex != null)
            {
                if (L_Ex is LokiException)
                {
                    ErrorMessageBox.Show((LokiException)L_Ex);
                }
                else
                    ErrorMessageBox.Show(LokiServices.Errors.BuildError<LokiException>(ErrorMessages.Application_UnhandledException, Log, L_Ex));
            }
            else
            {
                DXMessageBox.Show(e.Parameter.ToString(), UIValues.MessageBox_Error, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        protected CommandManager Commands { get; private set; }
        #endregion

        public string[] DataDefinitions { get; set; }

        public string[] ModelDefinitions { get; set; }

        public string[] VMDefinitions { get; set; }

        public string[] TemplatesDefinitions { get; set; }

        public string ThemeName { get; set; }
    }
}
